﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WPFCustomLayoutPanel
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:KazhOoComicsReader.UC"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:KazhOoComicsReader.UC;assembly=KazhOoComicsReader.UC"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:FilmStripPanel/>
    ///
    /// </summary>
    public class FilmStripPanel : StackPanel
    {
        private bool _eventHooked;

        // Make the panel as big as the biggest element
        protected override Size MeasureOverride(Size availableSize)
        {
            // get the list box
            var listBox = GetListBox();

            // hook into selection change to recalculate whenever the user clicks on a panel
            if (!_eventHooked && listBox != null)
            {
                listBox.SelectionChanged += (sender, e) => InvalidateArrange();
                _eventHooked = true;
            }

            Size t = base.MeasureOverride(availableSize);
            return t;
        }

        // Arrange the child elements to their final position
        protected override Size ArrangeOverride(Size finalSize)
        {
            var listBox = GetListBox();

            // nothing to do if there are no children or no list box
            if (listBox == null || Children.Count < 1)
            {
                return base.ArrangeOverride(finalSize);
            }

            // default selection
            if (listBox.SelectedIndex < 0)
            {
                listBox.SelectedIndex = 0;
            }

            var selectedIndex = listBox.SelectedIndex;

            if (this.Orientation == System.Windows.Controls.Orientation.Horizontal)
            {
                // first set up the selected panel
                var LeftPosSelectedIndex = (finalSize.Width / 2) - (Children[selectedIndex].DesiredSize.Width / 2);
                //var RightPosSelectedIndex = (finalSize.Width / 2) + (Children[selectedIndex].DesiredSize.Width / 2);
                Children[selectedIndex].Arrange(new Rect(LeftPosSelectedIndex, 0, Children[selectedIndex].DesiredSize.Width, Children[selectedIndex].DesiredSize.Height));

                // Then the Left
                var leftPosForLeft = LeftPosSelectedIndex;
                for (var leftCounter = selectedIndex - 1; leftCounter >= 0; leftCounter--)
                {
                    leftPosForLeft = leftPosForLeft - Children[leftCounter].DesiredSize.Width;
                    var finalRect = new Rect(leftPosForLeft, 0, Children[leftCounter].DesiredSize.Width, Children[leftCounter].DesiredSize.Height);
                    Children[leftCounter].Arrange(finalRect);
                }

                // and finish with the right
                var leftPosForRight = LeftPosSelectedIndex;
                for (var rightCounter = selectedIndex + 1; rightCounter < Children.Count; rightCounter++)
                {
                    leftPosForRight = leftPosForRight + Children[rightCounter].DesiredSize.Width;
                    var finalRect = new Rect(leftPosForRight, 0, Children[rightCounter].DesiredSize.Width, Children[rightCounter].DesiredSize.Height);
                    Children[rightCounter].Arrange(finalRect);
                }
            }
            else
            {
                // first set up the selected panel
                var TopPosSelectedIndex = (finalSize.Height / 2) - (Children[selectedIndex].DesiredSize.Height / 2);
                //var BottomPosSelectedIndex = (finalSize.Width / 2) + (Children[selectedIndex].DesiredSize.Width / 2);
                Children[selectedIndex].Arrange(new Rect(0, TopPosSelectedIndex, Children[selectedIndex].DesiredSize.Width, Children[selectedIndex].DesiredSize.Height));

                // Then the Left
                var TopPosForTop = TopPosSelectedIndex;
                for (var TopCounter = selectedIndex - 1; TopCounter >= 0; TopCounter--)
                {
                    TopPosForTop = TopPosForTop - Children[TopCounter].DesiredSize.Height;
                    var finalRect = new Rect(0, TopPosForTop, Children[TopCounter].DesiredSize.Width, Children[TopCounter].DesiredSize.Height);
                    Children[TopCounter].Arrange(finalRect);
                }

                // and finish with the right
                var leftPosForBottom = TopPosSelectedIndex;
                for (var rightCounter = selectedIndex + 1; rightCounter < Children.Count; rightCounter++)
                {
                    leftPosForBottom = leftPosForBottom + Children[rightCounter].DesiredSize.Height;
                    var finalRect = new Rect(0, leftPosForBottom, Children[rightCounter].DesiredSize.Width, Children[rightCounter].DesiredSize.Height);
                    Children[rightCounter].Arrange(finalRect);
                }
            }

            return finalSize;
        }

        // use the visual tree helper to walk up the tree until we find the parent list box
        private ListBox GetListBox()
        {
            var parent = VisualTreeHelper.GetParent(this);
            while (!(parent is ListBox) && parent != null)
            {
                parent = VisualTreeHelper.GetParent(parent);
            }
            return parent == null ? null : (ListBox)parent;
        }
    }
}
